let W = null
// 6.封装一个watcher类
class watcher {
  // watcher实例化的时候接受两个参数,一个是key所在的对象 一个是key
  constructor(Obj, key) {
    this.Obj = Obj
    this.key = key
    // w等于当前的实例
    W = this
    // 在get中使用w
    this.get()
    W = null;
  }
  //当组件内new Watcher的时候就是想得到一个值,所以封装一个get方法拿值
  get() {
    //一旦这样拿值,就会直接进入当前key的响应式的getter函数中
    return this.Obj[this.Obj]
  }
  // 在watcher内部封装一个函数,当通知我更新的时候,直接调用这个方法
  update() {
    console.log('有人通知我更新了' + this.get());
  }
}

// 5.定义一个dep类,用来收集依赖 和通知更新
class Dep {
  constructor() {
    //每次实例化Dep就会创建一个空的数组,然后用来保存所有的watcher
    this.subs = []
  }
  depend(watcher) {
    this.subs.push(watcher);
    console.log(
      "每次访问我的数据的时候,我就把watcher收集到dep.subs这个数组中",
      this.subs
    );
  }
  notify() {
    console.log("通知所有的watcher 重新加载新的数据");
    this.subs.forEach((watcher) => {
      watcher.update();
    });
  }
}
// 4.封装defineReactive函数,主要是为了对单个数据做数据劫持(数据劫持的核心的代码)
function defineReactive(_data, key, value) {
  // 把value值再次交给observe方法,进行深层次的数据响应
  observe(value)
  //每次对一个值进行响应式的时候,实例化一个Dep类
  const dep = new Dep();
  Object.defineProperty(_data, key, {
    // 获取值 将传入的值返回出去
    get() {
      // 当这个数据被请求的时候,把观察着watcher收集起来到dep.subs中
      if (W) {
        dep.depend(W);
      }
      return value
    },
    // 接受新的值 如果新的值和旧的值一样则直接return
    set(newValue) {
      if (newValue === value) return
      // 如果不一样就赋值
      value = newValue
      //当我的响应式数据被修改的时候,我们要通知dep.subs里的watcher进行更新
      dep.notify()
    }
  })
}
// 2封装一个server类,主要用来处理发布订阅模式的核心操作(响应式操作,收集依赖,通知更新)
class Server {
  // 构造器接受的是要被响应式处理的对象
  constructor(_data) {
    // 2.2.1把这个对象放在实例上,降落在任何原型方法中都可以访问这个实例上的数据
    this._data = _data
    // 2.2.2判断当前的数据类型
    if (Array.isArray(_data)) {
      this.ServerAry(_data)
    } else {
      this.ServerObj(_data)
    }
  }
  //在Server的原型对象上封装一个对数组操作的方法
  ServerAry(_data) {
    //当现在被操作的是数组的时候,我们不能直接使用defineProperty进行操作,但是我们要对数组内部的对象进行响应式操作
    _data.forEach((item) => {
      // 把数组的值交给observe函数继续监听
      observe(item)
    })
  }
  //在Server的原型对象上封装一个对对象操作的方法
  ServerObj(_data) {
    //将每一个数据的响应式核心代码交给defineReactive函数处理
    for (let key of Object.keys(_data)) {
      defineReactive(_data, key, _data[key])
    }
  }
  // 把每一个数据的响应式核心代码交给defineReactive函数处理 传入当前值 和属性 和属性对应的值
}
// 2.封装一个observe函数,接受_data的值,一个个的进行数据劫持
function observe(_data) {
  // 如果是对象的话执行
  if (_data instanceof Object) {
    new Server(_data)
  } else return
}
// 1.封装一个Vue的构造函数 接受一个配置对象
function Vue(options) {
  //将options配置对象内的data,放在实例对象this的_data属性上
  this._data = options.data;
  // 进行数据代理,把_data中的属性取出来,一个个的放在vue实例上
  for (let key of Object.keys(this._data)) {
    Object.defineProperty(this, key, {
      get() {
        return this._data[key]
      },
      set(newValue) {
        this._data[key] = newValue
      }
    })
  }
  observe(this._data)
}
// 实例化Vue
const vm = new Vue({
  data: {
    count: 0,
    Obj: { name: '罗飞', age: 18 },
    Ary: [
      { now: '晴天' },
      { today: "雨天" }
    ]
  }
})
function huoqu() {
  console.log(vm);
  vm.count++
  console.log(vm);
}
huoqu()